package com.example.func.aspect;

import com.example.func.annotation.AuditLog;
import com.example.func.enums.Scenario;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 审计日志切面
 * 处理 @AuditLog 注解标记的方法
 */
@Aspect
@Component
@Order(2)
@Slf4j
public class AuditLogAspect {

    @Autowired
    private ApplicationContext applicationContext;

    private final ExpressionParser parser = new SpelExpressionParser();

    @Around("@annotation(auditLog)")
    public Object around(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        String[] paramNames = signature.getParameterNames();
        
        // 构建参数映射
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            paramMap.put(paramNames[i], args[i]);
        }
        
        // 获取实体信息（如果配置了）
        Object entityBefore = null;
        Object entityAfter = null;
        Long entityId = null;
        
        if (!auditLog.serviceName().isEmpty() && !auditLog.entityIdParam().isEmpty()) {
            try {
                // 提取实体ID
                entityId = extractEntityId(auditLog.entityIdParam(), paramMap);
                
                if (entityId != null) {
                    // 获取实体变更前的状态
                    entityBefore = getEntityById(auditLog.serviceName(), auditLog.getEntityMethod(), entityId);
                }
            } catch (Exception e) {
                log.warn("获取实体变更前状态失败: {}", e.getMessage());
            }
        }
        
        // 记录请求信息
        if (auditLog.logRequest()) {
            logAuditInfo("REQUEST", auditLog, className, methodName, paramMap, entityBefore, null);
        }
        
        Object result = null;
        Throwable exception = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 获取实体变更后的状态
            if (entityId != null && auditLog.logEntityState()) {
                try {
                    entityAfter = getEntityById(auditLog.serviceName(), auditLog.getEntityMethod(), entityId);
                } catch (Exception e) {
                    log.warn("获取实体变更后状态失败: {}", e.getMessage());
                }
            }
            
            return result;
        } catch (Throwable e) {
            exception = e;
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            // 记录响应信息
            if (auditLog.logResponse()) {

            }
            
            // 记录异常信息
            if (exception != null) {

            }
        }
    }
    
    /**
     * 提取实体ID
     */
    private Long extractEntityId(String entityIdParam, Map<String, Object> paramMap) {
        try {
            // 支持SpEL表达式
            if (entityIdParam.startsWith("#")) {
                EvaluationContext context = new StandardEvaluationContext();
                paramMap.forEach(context::setVariable);
                
                Expression expression = parser.parseExpression(entityIdParam);
                Object value = expression.getValue(context);
                
                if (value instanceof Number) {
                    return ((Number) value).longValue();
                }
            } else {
                // 直接参数名
                Object value = paramMap.get(entityIdParam);
                if (value instanceof Number) {
                    return ((Number) value).longValue();
                }
            }
        } catch (Exception e) {
            log.warn("提取实体ID失败: {}", e.getMessage());
        }
        return null;
    }
    
    /**
     * 根据ID获取实体
     */
    private Object getEntityById(String serviceName, String methodName, Long id) {
        try {
            Object service = applicationContext.getBean(serviceName);
            Method method = service.getClass().getMethod(methodName, Long.class);
            return method.invoke(service, id);
        } catch (Exception e) {
            log.warn("获取实体失败 - serviceName: {}, methodName: {}, id: {}, error: {}", 
                serviceName, methodName, id, e.getMessage());
            return null;
        }
    }
    
    /**
     * 记录审计信息
     */
    private void logAuditInfo(String type, AuditLog auditLog, String className, String methodName, 
                             Map<String, Object> data, Object entityBefore, Object entityAfter) {
        
        // 构建审计日志信息
        Map<String, Object> auditInfo = new HashMap<>();
        auditInfo.put("type", type);
        auditInfo.put("timestamp", LocalDateTime.now());
        auditInfo.put("className", className);
        auditInfo.put("methodName", methodName);
        auditInfo.put("module", getModule(auditLog));
        auditInfo.put("operation", auditLog.opType().name());
        auditInfo.put("description", auditLog.description());
        auditInfo.put("level", auditLog.level().name());
        auditInfo.put("data", data);
        
        if (entityBefore != null) {
            auditInfo.put("entityBefore", entityBefore);
        }
        if (entityAfter != null) {
            auditInfo.put("entityAfter", entityAfter);
        }
        
        // 根据级别记录日志
        String logMessage = String.format("[AUDIT] %s - %s.%s - %s", 
            type, className, methodName, auditLog.description());
        
        switch (auditLog.level()) {
            case ERROR:
                log.error("{} - {}", logMessage, auditInfo);
                break;
            case WARN:
                log.warn("{} - {}", logMessage, auditInfo);
                break;
            case CRITICAL:
                log.error("[CRITICAL] {} - {}", logMessage, auditInfo);
                break;
            default:
                log.info("{} - {}", logMessage, auditInfo);
                break;
        }
    }
    
    /**
     * 获取模块名称
     */
    private String getModule(AuditLog auditLog) {
        if (!auditLog.module().isEmpty()) {
            return auditLog.module();
        }
        if (auditLog.scenario() != Scenario.NONE) {
            return auditLog.scenario().name();
        }
        return "UNKNOWN";
    }
}
